/**
 *
 */
package xin.xihc.validtor;

import xin.xihc.validtor.annotation.*;
import xin.xihc.validtor.annotation.Number;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

;

/**
 * 验证工具
 *
 * @author xihc
 * @version 1.0
 * @date 2018年09月18日
 */
public final class ValidateUtil {

    private static Map<Class<?>, BeanClassProp> classMap = new HashMap<Class<?>, BeanClassProp>();

    private ValidateUtil() {
    }

    /**
     * 开始验证表单对象
     *
     * @param val 表单
     * @return 表单验证结果
     */
    public static ValidateResult valid(Object val) {
        ValidateResult res = new ValidateResult();
        if (null == val) {
            res.toFail(null, "为空对象");
            return res;
        }

        BeanClassProp beanClassProp = getBeanClassProp(val.getClass());
        if (null == beanClassProp) {
            return res.toSuccess();
        }

        Map<String, Annotation[]> fieldAnnotations = beanClassProp.getFieldAnnotations();

        for (Field field : beanClassProp.getFields()) {
            field.setAccessible(true);

            try {
                Object obj_val = field.get(val);// 字段值

                if (!fieldAnnotations.containsKey(field.getName())) {// 没有注解的字段则跳过
                    continue;
                }

                Annotation[] validAnnotations = fieldAnnotations.get(field.getName());
                for (Annotation annotation : validAnnotations) {
                    if (annotation instanceof NotNull) { // 不能为null
                        if (null == obj_val) {
                            res.toFail(field.getName(), ((NotNull) annotation).msg());
                            return res;
                        }
                    } else if (annotation instanceof NotEmpty) {// 不能为空
                        if (isNullEmpty(obj_val)) {
                            res.toFail(field.getName(), ((NotEmpty) annotation).msg());
                            return res;
                        }
                    } else if (annotation instanceof Length) {// 长度校验
                        if (null == obj_val) {
                            if (((Length) annotation).min() > 0) {// 如果设置最小长度小于1时，可以为null
                                res.toFail(field.getName(), ((Length) annotation).msg());
                                return res;
                            } else { // 为null时，最小值小于1时，验证通过
                                res.toSuccess();
                                return res;
                            }
                        }
                        int temp = 0;
                        if (field.getType().isArray()) { // 数组
                            temp = ((Object[]) obj_val).length;
                        } else if (List.class.isAssignableFrom(field.getType())) {// 列表
                            temp = ((List<?>) obj_val).size();
                        } else {// 字符串
                            temp = obj_val.toString().trim().length();
                        }
                        if (temp < ((Length) annotation).min()) {
                            res.toFail(field.getName(), ((Length) annotation).msg());
                            return res;
                        }
                        if (temp > ((Length) annotation).max()) {
                            res.toFail(field.getName(), ((Length) annotation).msg());
                            return res;
                        }
                    } else if (annotation instanceof Number) {// 数值校验
                        if (null == obj_val) {
                            res.toFail(field.getName(), ((Number) annotation).msg());
                            return res;
                        }
                        Number numberAnno = (Number) annotation;

                        // 校验数值大小
                        try {
                            Double valueOf = Double.valueOf(obj_val.toString());
                            if (valueOf.compareTo(numberAnno.min()) < 0) {// 小于最小值
                                res.toFail(field.getName(), numberAnno.msg());
                                return res;
                            }
                            if (valueOf.compareTo(numberAnno.max()) > 0) {// 小于最小值
                                res.toFail(field.getName(), numberAnno.msg());
                                return res;
                            }
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                            res.toFail(field.getName(), numberAnno.msg());
                            return res;
                        }

                        if (numberAnno.precision() >= 0) { // 验证精度
                            int temp = 0;
                            if (obj_val.toString().indexOf(".") > 0) {
                                temp = obj_val.toString().length() - obj_val.toString().indexOf(".") - 1;
                            }
                            if (temp > numberAnno.precision()) {
                                res.toFail(field.getName(), numberAnno.msg());
                                return res;
                            }
                        }

                    } else if (annotation instanceof Regx) {// 正则校验
                        if (null == obj_val) {
                            res.toFail(field.getName(), ((Regx) annotation).msg());
                            return res;
                        }
                        String[] regxs = ((Regx) annotation).regx();

                        for (String regx : regxs) {
                            if (isNullEmpty(regx)) {
                                continue;
                            }
                            boolean b = Pattern.matches(regx, obj_val.toString());
                            if (!b) {
                                res.toFail(field.getName(), ((Regx) annotation).msg());
                                return res;
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
        return res;
    }

    /**
     * 先通过缓存取，如没有则加载到缓存
     *
     * @param clazz
     * @return
     */
    private static BeanClassProp getBeanClassProp(Class<?> clazz) {
        if (classMap.containsKey(clazz)) {
            return classMap.get(clazz);
        }
        BeanClassProp res = new BeanClassProp();
        res.setClazz(clazz);
        List<Field> allFields = getAllFields(clazz, false, false);
        if (allFields.size() < 1) {
            return null;
        }
        res.setFields(allFields.toArray(new Field[allFields.size()]));
        Annotation[] validAnnotations;
        for (int i = 0; i < allFields.size(); i++) {
            allFields.get(i).setAccessible(true);
            validAnnotations = allFields.get(i).getAnnotations();
            if (validAnnotations.length > 0) {
                res.getFieldAnnotations().put(allFields.get(i).getName(), validAnnotations);
            }
        }
        classMap.put(clazz, res);
        return res;
    }

    /**
     * 获取该对象的所有字段(包含父类的)
     *
     * @param clazz
     * @return
     */
    private static List<Field> getAllFields(Class<?> clazz, boolean containFinal, boolean containStatic) {
        List<Field> res = new ArrayList<Field>(10);
        if (null == clazz) {
            return res;
        }
        ArrayList<Field> temp = null;
        while (!clazz.equals(Object.class)) {
            temp = new ArrayList<Field>(10);
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                if (!containStatic && Modifier.isStatic(field.getModifiers())) {
                    continue;
                }
                if (!containFinal && Modifier.isFinal(field.getModifiers())) {
                    continue;
                }
                temp.add(field);
            }
            res.addAll(0, temp);
            clazz = clazz.getSuperclass();
        }
        return res;
    }

    /**
     * 判断对象是否为空
     *
     * @param obj
     * @return true-对象obj为空
     */
    private final static boolean isNullEmpty(Object obj) {
        if (null == obj) {
            return true;
        } else {
            if ((obj instanceof String)) {
                return "".equals(((String) obj).trim());
            }
            if (obj.getClass().isArray()) {
                return ((Object[]) obj).length < 1;
            }
            if ((obj instanceof List)) {
                return ((List<?>) obj).size() < 1;
            }
        }
        return false;
    }

}
